/**
 * 代码生成器页面逻辑
 *
 * @版权所有 rem.studio
 */
import React, { PureComponent, Fragment } from 'react';
import { formatMessage } from 'umi-plugin-react/locale';
import { connect } from 'dva';
import moment from 'moment';
import { Row, Col, Card, Form, Input, Select, Button, Modal, message, Divider, Radio, Popconfirm, Icon, Table } from 'antd';
import PageHeaderWrapper from '@/components/PageHeaderWrapper';
import { saveAs } from 'file-saver';
import ProTable from '@ant-design/pro-table';

import styles from './DevTool.less';

const FormItem = Form.Item;
const { Option } = Select;
const RadioGroup = Radio.Group;
const InputGroup = Input.Group;
const InputPassword = Input.Password;
const getValue = obj => Object.keys(obj).map(key => obj[key]).join(',');

// 带单元格编辑功能的表格
const EditableContext = React.createContext();

const EditableRow = ({ form, index, ...props }) => (
  <EditableContext.Provider value={form}>
    <tr {...props} />
  </EditableContext.Provider>
);

const EditableFormRow = Form.create()(EditableRow);

class EditableCell extends React.Component {
  state = {
    editing: false,
  };

  toggleEdit = () => {
    const editing = !this.state.editing;
    this.setState({ editing }, () => {
      if (editing) {
        this.input.focus();
      }
    });
  };

  save = e => {
    const { record, handleSave } = this.props;
    this.form.validateFields((error, values) => {
      if (error && error[e.currentTarget.id]) {
        return;
      }
      this.toggleEdit();
      handleSave({ ...record, ...values });
    });
  };

  renderCell = form => {
    this.form = form;
    const { children, dataIndex, record /** , title **/ } = this.props;
    const { editing } = this.state;
    return editing ? (
      <Form.Item style={{ margin: 0 }}>
        {form.getFieldDecorator(dataIndex, {
          rules: [
            {
              required: true,
              message: formatMessage({ id: 'app.common.required' })
            },
          ],
          initialValue: record[dataIndex],
        })(
          dataIndex === 'fieldType' ?
            <Select ref={node => (this.input = node)} onPressEnter={this.save} onBlur={this.save} placeholder={formatMessage({ id: 'app.common.choose' })} style={{ width: '100%' }}>
              <Option key='String'>String</Option>
              <Option key='boolean'>boolean</Option>
              <Option key='byte'>byte</Option>
              <Option key='short'>short</Option>
              <Option key='int'>int</Option>
              <Option key='long'>long</Option>
              <Option key='float'>float</Option>
              <Option key='double'>double</Option>
              <Option key='BigDecimal'>BigDecimal</Option>
              <Option key='Date'>Date</Option>
              <Option key='Time'>Time</Option>
              <Option key='Timestamp'>Timestamp</Option>
            </Select>
            :
            <Input placeholder={formatMessage({ id: 'app.generator.entityfieldtip' })} ref={node => (this.input = node)} onPressEnter={this.save} onBlur={this.save} />
        )}
      </Form.Item>
    ) : (
        <div
          className="editable-cell-value-wrap"
          style={{ paddingRight: 24 }}
          onClick={this.toggleEdit}
        >
          {children}
        </div>
      );
  };

  render() {
    const {
      editable,
      dataIndex,
      title,
      record,
      index,
      handleSave,
      children,
      ...restProps
    } = this.props;
    return (
      <td {...restProps}>
        {editable ? (
          <EditableContext.Consumer>{this.renderCell}</EditableContext.Consumer>
        ) : (
            children
          )}
      </td>
    );
  }
}

// 包含带单元格编辑功能的表格的Modal
@Form.create()
class UpdateForm extends PureComponent {
  static defaultProps = {
    handleUpdate: () => { },
    handleUpdateModalVisible: () => { },
    values: {}
  };

  constructor(props) {
    super(props);

    this.state = {
      formVals: {
        moduleName: props.values.moduleName,
        serviceName: props.values.serviceName,
        packageName: props.values.packageName,
        entityName: props.values.entityName,
        tableName: props.values.tableName,
        idName: props.values.idName,
        id: props.values.id
      },
      dataSource: props.values.id ? props.fieldDataSource.list : [],
      count: props.values.id ? props.fieldDataSource.count : 0
    };

    this.formLayout = {
      labelCol: { span: 6 },
      wrapperCol: { span: 15 }
    };

    this.columns = [
      {
        title: formatMessage({ id: 'app.notification.type' }),
        dataIndex: 'fieldType',
        width: '30%',
        editable: true,
      },
      {
        title: formatMessage({ id: 'app.generator.entityfield' }),
        dataIndex: 'field',
        editable: true,
      },
      {
        title: formatMessage({ id: 'app.common.operate' }),
        align: 'center',
        dataIndex: 'operation',
        render: (text, record) =>
          this.state.dataSource.length >= 1 ? (
            <Popconfirm title={formatMessage({ id: 'app.common.confirm-delete' })} onConfirm={() => this.handleDelete(record)}>
              <a><Icon type="delete" />{formatMessage({ id: 'app.common.delete' })}</a>
            </Popconfirm>
          ) : null,
      },
    ];
  }

  handleDelete = record => {
    const dataSource = [...this.state.dataSource];
    this.setState({ dataSource: dataSource.filter(item => item.id !== record.id) });
  };

  handleAdd = () => {
    const { count, dataSource } = this.state;
    const newData = {
      id: count,
      fieldType: `-`,
      field: `-`,
    };
    this.setState({
      dataSource: [...dataSource, newData],
      count: count + 1
    });
  };

  handleSave = row => {
    const newData = [...this.state.dataSource];
    const index = newData.findIndex(item => row.id === item.id);
    const item = newData[index];
    newData.splice(index, 1, {
      ...item,
      ...row,
    });
    this.setState({ dataSource: newData });
  };

  renderContent = (formVals) => {
    const { form } = this.props;

    return [
      <Row key="moduleNameRow" gutter={16}>
        <Col key="moduleNameCol" span={12}>
          <FormItem key="moduleName" {...this.formLayout} label={formatMessage({ id: 'app.generator.modulename' })}>
            {form.getFieldDecorator('moduleName', {
              rules: [
                {
                  required: true,
                  message: formatMessage({ id: 'validation.modulename.required' })
                },
                {
                  message: formatMessage({ id: 'validation.modulename.length' }),
                  max: 64
                }
              ],
              initialValue: formVals.moduleName
            })(<Input placeholder={formatMessage({ id: 'app.common.enter' })} />)}
          </FormItem>
        </Col>
        <Col key="serviceNameCol" span={12}>
          <FormItem key="serviceName" {...this.formLayout} label={formatMessage({ id: 'app.generator.servicename' })}>
            {form.getFieldDecorator('serviceName', {
              rules: [
                {
                  required: true,
                  message: formatMessage({ id: 'validation.servicename.required' })
                },
                {
                  message: formatMessage({ id: 'validation.servicename.length' }),
                  max: 64
                }
              ],
              initialValue: formVals.serviceName
            })(<Input placeholder={formatMessage({ id: 'app.common.enter' })} />)}
          </FormItem>
        </Col>
      </Row>,
      <Row key="packageNameRow" gutter={16}>
        <Col key="packageNameCol" span={12}>
          <FormItem key="packageName" {...this.formLayout} label={formatMessage({ id: 'app.generator.packagename' })}>
            {form.getFieldDecorator('packageName', {
              rules: [
                {
                  required: true,
                  message: formatMessage({ id: 'validation.packagename.required' })
                },
                {
                  message: formatMessage({ id: 'validation.packagename.length' }),
                  max: 256
                }
              ],
              initialValue: formVals.packageName
            })(<Input placeholder={formatMessage({ id: 'app.common.enter' })} />)}
          </FormItem>
        </Col>
        <Col key="entityNameCol" span={12}>
          <FormItem key="entityName" {...this.formLayout} label={formatMessage({ id: 'app.generator.entityname' })}>
            {form.getFieldDecorator('entityName', {
              rules: [
                {
                  required: true,
                  message: formatMessage({ id: 'validation.entityname.required' })
                },
                {
                  message: formatMessage({ id: 'validation.entityname.length' }),
                  max: 64
                }
              ],
              initialValue: formVals.entityName
            })(<Input placeholder={formatMessage({ id: 'app.common.enter' })} />)}
          </FormItem>
        </Col>
      </Row>,
      <Row key="tableNameRow" gutter={16}>
        <Col key="tableNameCol" span={12}>
          <FormItem key="tableName" {...this.formLayout} label={formatMessage({ id: 'app.generator.tablename' })}>
            {form.getFieldDecorator('tableName', {
              rules: [
                {
                  required: true,
                  message: formatMessage({ id: 'validation.tablename.required' })
                },
                {
                  message: formatMessage({ id: 'validation.tablename.length' }),
                  max: 64
                }
              ],
              initialValue: formVals.tableName
            })(<Input placeholder={formatMessage({ id: 'app.common.enter' })} />)}
          </FormItem>
        </Col>
        <Col key="idNameCol" span={12}>
          <FormItem key="idName" {...this.formLayout} label={formatMessage({ id: 'app.generator.idname' })}>
            {form.getFieldDecorator('idName', {
              rules: [
                {
                  required: true,
                  message: formatMessage({ id: 'validation.idname.required' })
                },
                {
                  message: formatMessage({ id: 'validation.idname.length' }),
                  max: 32
                }
              ],
              initialValue: formVals.idName
            })(<Input placeholder={formatMessage({ id: 'app.common.enter' })} />)}
          </FormItem>
        </Col>
      </Row>
    ];
  };

  render() {
    const { updateModalVisible, handleUpdateModalVisible, values } = this.props;
    const { formVals, dataSource, count } = this.state;
    const okUpdateHandle = () => {
      const { form, handleUpdate } = this.props;
      const { formVals: oldValue } = this.state;
      form.validateFields((err, fieldsValue) => {
        if (err) return;
        const formVals = { ...oldValue, ...fieldsValue };
        this.setState(
          {
            formVals
          },
          () => {
            formVals.dataSource = dataSource;
            handleUpdate(formVals);
          }
        );
      });
    };

    const components = {
      body: {
        row: EditableFormRow,
        cell: EditableCell,
      },
    };
    const columns = this.columns.map(col => {
      if (!col.editable) {
        return col;
      }
      return {
        ...col,
        onCell: record => ({
          record,
          editable: col.editable,
          dataIndex: col.dataIndex,
          title: col.title,
          handleSave: this.handleSave,
        }),
      };
    });

    return (
      <Modal
        destroyOnClose
        width={720}
        title={values.id ? formatMessage({ id: 'app.generator.edit-generator' }) : formatMessage({ id: 'app.generator.add-generator' })}
        visible={updateModalVisible}
        onOk={okUpdateHandle}
        onCancel={() => handleUpdateModalVisible(false, values)}
        afterClose={() => handleUpdateModalVisible()}
      >
        {this.renderContent(formVals)}
        <Button onClick={this.handleAdd} type="primary" style={{ marginBottom: 16 }}>
          {formatMessage({ id: 'app.common.add' }) + formatMessage({ id: 'app.generator.entityfield' })}
        </Button>
        <h4>{formatMessage({ id: 'app.generator.data-title' })}</h4>
        <Table
          rowKey="id"
          components={components}
          rowClassName={() => 'editable-row'}
          bordered
          dataSource={dataSource}
          columns={columns}
        />
      </Modal>
    );
  }
}

/* eslint react/no-multi-comp:0 */
@connect(({ generator, loading }) => ({
  generator,
  loading: loading.models.generator,
}))
@Form.create()
class Generator extends PureComponent {
  state = {
    updateModalVisible: false,
    selectedRows: [],
    formValues: {},
    updateFormValues: {},
    fieldDataSource: {},
    hiddenMenuButton: localStorage.getItem('cancersystem_menubutton')
  };

  columns = [
    {
      title: formatMessage({ id: 'app.generator.modulename' }),
      dataIndex: 'moduleName'
    },
    {
      title: formatMessage({ id: 'app.generator.servicename' }),
      copyable: true,
      ellipsis: true,
      dataIndex: 'serviceName'
    },
    {
      title: formatMessage({ id: 'app.generator.packagename' }),
      copyable: true,
      ellipsis: true,
      dataIndex: 'packageName'
    },
    {
      title: formatMessage({ id: 'app.generator.entityname' }),
      dataIndex: 'entityName'
    },
    {
      title: formatMessage({ id: 'app.generator.tablename' }),
      copyable: true,
      ellipsis: true,
      dataIndex: 'tableName'
    },
    {
      title: formatMessage({ id: 'app.generator.idname' }),
      dataIndex: 'idName'
    },
    {
      title: formatMessage({ id: 'app.common.create-time' }),
      dataIndex: 'createTime',
      width: '12%',
      sorter: true,
      render: val => <span>{moment(val).format('YYYY-MM-DD HH:mm:ss')}</span>
    },
    {
      title: formatMessage({ id: 'app.common.operate' }),
      align: 'center',
      width: '14%',
      render: (text, record) => (
        <Fragment>
          {this.state.hiddenMenuButton.indexOf('generator:update') !== -1 ? null :
            <a onClick={() => this.handleUpdateModalVisible(true, record)}><Icon type="edit" />{formatMessage({ id: 'app.common.edit' })}</a>
          }
          <Divider type="vertical" />
          <Popconfirm title={formatMessage({ id: 'app.common.confirm-delete' })} onConfirm={() => this.deleteItem(record.id)}>
            {this.state.hiddenMenuButton.indexOf('generator:delete') !== -1 ? null :
              <a><Icon type="delete" />{formatMessage({ id: 'app.common.delete' })}</a>
            }
          </Popconfirm>
        </Fragment>
      )
    }
  ];

  componentDidMount() {
    const { dispatch } = this.props;
    dispatch({
      type: 'generator/fetch'
    });
  }

  handleBasicTableChange = (pagination, filtersArg, sorter) => {
    const { dispatch } = this.props;
    const { formValues } = this.state;

    const filters = Object.keys(filtersArg).reduce((obj, key) => {
      const newObj = { ...obj };
      newObj[key] = getValue(filtersArg[key]);
      return newObj;
    }, {});

    const params = {
      currentPage: pagination.current,
      pageSize: pagination.pageSize,
      ...formValues,
      ...filters
    };
    if (sorter.field) {
      params.sorter = `${sorter.field}_${sorter.order}`;
    }

    dispatch({
      type: 'generator/fetch',
      payload: params
    });
  };

  handleFormReset = () => {
    const { form, dispatch } = this.props;
    form.resetFields();
    this.setState({
      formValues: {}
    });
    dispatch({
      type: 'generator/fetch',
      payload: {}
    });
  };

  deleteItem = id => {
    const { dispatch } = this.props;
    dispatch({
      type: 'generator/delete',
      payload: {
        id: id
      }
    }).then(response => {
      if (response.message == 'success') {
        this.setState({
          selectedRows: []
        });
        message.success(formatMessage({ id: 'app.common.delete-success' }));
      } else {
        message.warning(response.message);
      }
      dispatch({
        type: 'generator/fetch',
        payload: {}
      });
    });
  }

  handleDeleteClick = () => {
    const { selectedRows } = this.state;

    if (selectedRows.length === 0) {
      message.warning(formatMessage({ id: 'app.common.choose-delete' }));
      return;
    }

    Modal.confirm({
      title: formatMessage({ id: 'app.common.batch-delete' }),
      content: formatMessage({ id: 'app.common.confirm-batch-delete' }),
      okText: formatMessage({ id: 'app.common.confirm' }),
      cancelText: formatMessage({ id: 'app.common.cancel' }),
      onOk: () => this.deleteItem(selectedRows.map(row => row.id)),
    });
  };

  handleSelectRows = rows => {
    this.setState({
      selectedRows: rows
    });
  };

  handleSearch = e => {
    if (e) {
      e.preventDefault();
    }
    const { dispatch, form } = this.props;
    form.validateFields((err, fieldsValue) => {
      if (err) return;
      const values = {
        ...fieldsValue
      };
      this.setState({
        formValues: values
      });
      dispatch({
        type: 'generator/fetch',
        payload: values
      });
    });
  };

  handleUpdateModalVisible = (flag, record) => {
    if (flag == true && record.id) {
      const { dispatch } = this.props;
      dispatch({
        type: 'generator/fetchFieldData',
        payload: {
          generatorId: record.id,
          version: 'react'
        }
      }).then(response => {
        this.setState({
          updateModalVisible: !!flag,
          updateFormValues: record || {}
        });
      });
    } else {
      this.setState({
        updateModalVisible: !!flag,
        updateFormValues: record || {}
      });
    }
  };

  handleExport = e => {
    e.preventDefault();
    const { dispatch, form } = this.props;
    form.validateFields((err, fieldsValue) => {
      if (err) return;
      const values = {
        ...fieldsValue
      };
      this.setState({
        formValues: values
      });
      dispatch({
        type: 'generator/export',
        payload: values
      }).then(response => {
        saveAs(response, formatMessage({ id: 'app.generator.generator-manage' }) + '.xlsx');
        dispatch({
          type: 'generator/fetch',
          payload: values
        });
      });
    });
  };

  handleUpdate = fields => {
    const { dispatch } = this.props;

    let fieldArray = [];
    for (let id in fields.dataSource) {
      fieldArray.push(fields.dataSource[id].field);
    }
    let newFieldArray = fieldArray.join(",") + ",";
    for (let i = 0; i < fieldArray.length; i++) {// 判断实体字段是否重复
      if (newFieldArray.replace(fieldArray[i] + ",", "").indexOf(fieldArray[i] + ",") > -1) {
        message.warning(formatMessage({ id: 'app.generator.entityfieldduplicate' }));
        return;
      }
    }

    if (fields.id) {
      dispatch({
        type: 'generator/update',
        payload: {
          body: {
            moduleName: fields.moduleName,
            serviceName: fields.serviceName,
            packageName: fields.packageName,
            entityName: fields.entityName,
            tableName: fields.tableName,
            idName: fields.idName,
            generatorField: fields.dataSource,
            id: fields.id
          },
        },
      }).then(response => {
        if (response.message == 'success') {
          message.success(formatMessage({ id: 'app.common.edit-success' }));
          this.handleUpdateModalVisible();
        } else {
          message.warning(response.message);
        }
        dispatch({
          type: 'generator/fetch',
          payload: {}
        });
      });
    } else {
      dispatch({
        type: 'generator/add',
        payload: {
          moduleName: fields.moduleName,
          serviceName: fields.serviceName,
          packageName: fields.packageName,
          entityName: fields.entityName,
          tableName: fields.tableName,
          idName: fields.idName,
          generatorField: fields.dataSource
        }
      }).then(response => {
        if (response.message == 'success') {
          message.success(formatMessage({ id: 'app.common.add-success' }));
          this.handleUpdateModalVisible();
        } else {
          message.warning(response.message);
        }
        dispatch({
          type: 'generator/fetch',
          payload: {}
        });
      });
    }
  };

  handleGenerateClick = () => {
    const { selectedRows } = this.state;
    if (selectedRows.length === 0) {
      message.warning(formatMessage({ id: 'app.generator.choose-generate' }));
      return;
    }
    this.generateResource(selectedRows.map(row => row.id));
  };

  //生成
  generateResource = id => {
    const { dispatch } = this.props;
    dispatch({
      type: 'generator/generate',
      payload: {
        id: id
      }
    }).then(response => {
      saveAs(response, formatMessage({ id: 'app.generator.generate' }) + '.zip');
      dispatch({
        type: 'generator/fetch',
        payload: {}
      });
    });
  };

  renderSimpleForm() {
    const { form: { getFieldDecorator } } = this.props;
    return (
      <Form onSubmit={this.handleSearch} layout="inline">
        <Row gutter={{ md: 8, lg: 24, xl: 48 }}>
          <Col md={8} sm={24}>
            <FormItem label={formatMessage({ id: 'app.generator.modulename' })}>
              {getFieldDecorator('moduleName')(<Input placeholder={formatMessage({ id: 'app.common.enter' })} />)}
            </FormItem>
          </Col>
          <Col md={8} sm={24}>
            <FormItem label={formatMessage({ id: 'app.generator.servicename' })}>
              {getFieldDecorator('serviceName')(<Input placeholder={formatMessage({ id: 'app.common.enter' })} />)}
            </FormItem>
          </Col>
          <Col md={8} sm={24}>
            <span className={styles.submitButtons}>
              <Button type="primary" htmlType="submit" icon="search">
                {formatMessage({ id: 'app.common.query' })}
              </Button>
              <Button style={{ marginLeft: 8 }} onClick={this.handleFormReset} type="primary" icon="reload">
                {formatMessage({ id: 'app.common.reset' })}
              </Button>
            </span>
          </Col>
        </Row>
      </Form>
    );
  }

  renderForm() {
    return this.renderSimpleForm();
  }

  render() {
    const { generator: { data, fieldData }, loading } = this.props;
    const { /**selectedRows,**/  updateModalVisible, updateFormValues } = this.state;
    const updateMethods = {
      handleUpdateModalVisible: this.handleUpdateModalVisible,
      handleUpdate: this.handleUpdate
    };
    let fieldDataSource;
    if ({ fieldData }.fieldData) {
      fieldDataSource = { fieldData }.fieldData;
    }
    const rowSelection = {
      onChange: (selectedRowKeys, selectedRows) => {
        this.handleSelectRows(selectedRows);
      }
    };
    return (
     <div content={formatMessage({ id: 'app.generator.generator-manage' })}>
        <Card bordered={false}>
          <div className={styles.tableList}>
            <div className={styles.tableListForm}>{this.renderForm()}</div>
            <div className={styles.tableListOperator}>
              {this.state.hiddenMenuButton.indexOf('generator:add') !== -1 ? null :
                <Button icon="plus" type="primary" onClick={() => this.handleUpdateModalVisible(true, { id: undefined })}>
                  {formatMessage({ id: 'app.common.add' })}
                </Button>
              }
              {this.state.hiddenMenuButton.indexOf('generator:generate') !== -1 ? null :
                <Button icon="plus-circle" type="primary" onClick={this.handleGenerateClick}>
                  {formatMessage({ id: 'app.generator.generate' })}
                </Button>
              }
              {this.state.hiddenMenuButton.indexOf('generator:export') !== -1 ? null :
                <Button icon="file-excel" type="primary" onClick={this.handleExport}>
                  {formatMessage({ id: 'app.common.export' })}
                </Button>
              }
              {this.state.hiddenMenuButton.indexOf('generator:delete') !== -1 ? null :
                <Button icon="delete" type="danger" ghost onClick={this.handleDeleteClick}>
                  {formatMessage({ id: 'app.common.batch-delete' })}
                </Button>
              }
            </div>
            <ProTable
              bordered={true}
              search={false}
              rowKey={record => record.id}
              rowSelection={rowSelection}
              loading={loading}
              dataSource={data ? data.list : []}
              pagination={data ? data.pagination : {}}
              columns={this.columns}
              onChange={this.handleBasicTableChange}
              options={{
                density: true,
                reload: () => {
                  this.handleSearch();
                },
                fullScreen: true,
                setting: true,
              }}
            />
          </div>
        </Card>
        {updateFormValues && Object.keys(updateFormValues).length ? (
          <UpdateForm
            {...updateMethods}
            updateModalVisible={updateModalVisible}
            values={updateFormValues}
            fieldDataSource={fieldDataSource}
            dispatch={this.props.dispatch}
          />
        ) : null}
     </div>
    );
  }
}

export default Generator;
